package org.jasig.cas.adaptors.jdbc;

import com.hyjx.framework.common.PropertyUtil;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.PreventedException;
import org.jasig.cas.authentication.UsernamePasswordCredential;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import javax.validation.constraints.NotNull;
import java.security.GeneralSecurityException;


/**
 * Class that if provided a query that returns a password (parameter of query
 * must be username) will compare that password to a translated version of the
 * password provided by the user. If they match, then authentication succeeds.
 * Default password translator is plaintext translator.
 *
 * @author Scott Battaglia
 * @author Dmitriy Kopylenko
 * @author Marvin S. Addison
 *
 * @since 3.0.0
 */
@Component("queryDatabaseAuthenticationHandler")
public class QueryDatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler {

    @NotNull
    private String sql;

    @NotNull
    private String adminSql;

    @Override
    protected final HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential)
            throws GeneralSecurityException, PreventedException {
    	
    	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    	String ck = String.valueOf(request.getSession().getAttribute("validationCode"));
    	String uck = request.getParameter("check");
    	
    	if(ck==null || !ck.equalsIgnoreCase(uck))
    	{
    		request.setAttribute("checkcode", "false");
    		throw new FailedLoginException("验证码不正确");
    	}

    	if(StringUtils.isBlank(this.sql)){
            this.sql = PropertyUtil.getGlobalObj().getProperty("cas.jdbc.authn.query.sql");
        }
        if (StringUtils.isBlank(this.sql) || getJdbcTemplate() == null) {
            throw new GeneralSecurityException("Authentication handler is not configured correctly");
        }

        final String username = credential.getUsername();
        final String encryptedPassword = this.getPasswordEncoder().encode(credential.getPassword());

        String userId;
        try {

            userId = getJdbcTemplate().queryForObject(this.sql, String.class, new Object[]{username, encryptedPassword});
        	
            if (StringUtils.isBlank(userId)) {
            	throw new FailedLoginException("Password does not match value on record.");
            }
        } catch (final IncorrectResultSizeDataAccessException e) {
            try {
                userId = getJdbcTemplate().queryForObject(this.adminSql, String.class, new Object[]{username, encryptedPassword});
            } catch (DataAccessException e1) {
                if (e.getActualSize() == 0) {
                    throw new AccountNotFoundException(username + " not found with SQL query");
                } else {
                    throw new FailedLoginException("Multiple records found for " + username);
                }
            }
        } catch (final DataAccessException e) {
            throw new PreventedException("SQL exception while executing query for " + username, e);
        }

/*        Map loginModel = getJdbcTemplate().queryForMap(this.userInfoSql, String.class, username);

        request.getSession().setAttribute("USER_INFO", loginModel);*/
        return createHandlerResult(credential, new SimplePrincipal(userId), null);
    }

    /**
     * @param sql The sql to set.
     */
    @Autowired
    public void setSql(@Value("${cas.jdbc.authn.query.sql:}") final String sql) {
        this.sql = sql;
    }
    /**
     * @param adminSql The sql to set.
     */
    @Autowired
    public void setAdminSql(@Value("${cas.jdbc.authn.query.adminSql:}") final String adminSql) {
        this.adminSql = adminSql;
    }

    @Override
    @Autowired(required = false)
    public void setDataSource(@Qualifier("dataSource") final DataSource dataSource) {
        super.setDataSource(dataSource);
    }
}
